package com.zhentao.config;

import cn.hutool.json.JSONUtil;

import com.zhentao.domain.YdUser;
import com.zhentao.filter.JwtFilter;
import com.zhentao.util.JwtUtil;
import com.zhentao.util.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import java.util.HashMap;
import java.util.Map;


@EnableWebSecurity
@Configuration
public class SecurityConfig {

    @Autowired
    private JwtFilter jwtFilter;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

//        关闭csrf
        http.csrf(AbstractHttpConfigurer::disable);
//        引入动态权限
        http.authorizeHttpRequests(config -> {
            config.requestMatchers(new AntPathRequestMatcher("/*")).permitAll()
                    .anyRequest().authenticated();
        });
//        登录
        http.formLogin(config -> {
            config.loginProcessingUrl("/login")
                    .successHandler((request, response, authentication) -> {
                        response.setContentType("application/json;charset=utf-8");
                        YdUser tuser = (YdUser) authentication.getPrincipal();
                        Map<String, Object> map = new HashMap<>();
                        map.put("uid", tuser.getId());
                        map.put("username", tuser.getUsername());
                        map.put("perms", tuser.getPerms());
//                        将tuser的Id生成token 并将token当成key,将tuser对象当成value 存入redis 返回token
                        String token = JwtUtil.createToken(map);
                        response.getWriter().println(JSONUtil.toJsonStr(Result.success().put("token", token)));
                    })
                    .failureHandler((request, response, exception) -> {
                        response.setContentType("application/json;charset=utf-8");
                        response.getWriter().println(JSONUtil.toJsonStr(Result.error(401, "登录失败")));
                    });
        });
//        处理异常
        http.exceptionHandling(config -> {
            config.accessDeniedHandler((request, response, accessDeniedException) -> {
                        response.setContentType("application/json;charset=utf-8");
                        response.getWriter().println(JSONUtil.toJsonStr(Result.error("权限不足")));
                    })
                    .authenticationEntryPoint((request, response, authException) -> {
                        response.setContentType("application/json;charset=utf-8");
                        response.getWriter().println(JSONUtil.toJsonStr(Result.error("登录失效")));
                    });
        });
//        关闭session
        http.sessionManagement(config -> {
            config.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        });
//        引入过滤器
        http.addFilterBefore(jwtFilter, LogoutFilter.class);
//        http.cors(conf->conf.configurationSource(corsConfiguration()));
//        退出登录
        http.logout(config -> {
            config.logoutUrl("/logout").logoutSuccessHandler((request, response, authentication) -> {
                response.setContentType("application/json;charset=utf-8");
                response.getWriter().println(JSONUtil.toJsonStr(Result.success("退出成功")));
            });
        });


        return http.build();
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(8);
    }

}
